import { ipcRenderer } from "electron";
import Vue from 'vue'
import _ from 'lodash';
import { LOWDB_CONN, LOWDB_GET } from "../bglib/lowdb_easy";

declare module 'vue/types/vue' {
    interface Vue {
        $ipcR: ipcHelper
    }
}

/** 交互参数 */
interface ipcSendOptions {
    /** 事件频道 */
    channel: string
    /** 返回事件的频道后缀 */
    return_key?: string
    /** 等待超时时间 */
    timeout?: number
    only_resolve?: boolean
}


/** 进行前后台交互时的数据定义集合 */
export interface IpcSendTypes {
    "example": IpcSendTypeNode<string, string>
}

/** 进行前后台交互时的数据接口 */
export interface IpcSendTypeNode<Targ, Tret> {
    /** 输入给后台的参数 */
    arg: Targ,
    /** 反馈给前台的结果 */
    ret: Tret
}

/** 连接数据库的基本配置 */
export interface IpcConnnectionBase {
    /** 数据库连接的关键字，用于识别的唯一值 */
    key: string
}

/** 通过文件名连接数据库 */
export interface IpcConnnectionFile extends IpcConnnectionBase {
    /** 数据库文件名 */
    file: string
}

/** 通过路径在数据库连接上取值 */
export interface IpcConnnectionGetByPath extends IpcConnnectionBase {
    /** 获取的路径 */
    path: string
}

/** 通过路径在数据库连接上设置数据 */
export interface IpcConnnectionSetByPath<TValue> extends IpcConnnectionBase {
    /** 路径 */
    path: string
    /** 要设置的值。要注意其值将会经过JSON序列化，某些类型的数值将会丢失 */
    value?: TValue
}

/** 反馈结果的基本信息 */
export interface IpcReturnBase {
    /** 反馈状态 */
    status: IpcReturnStatus | string,
    /** 反馈信息 */
    message: string
}

/** 反馈状态的枚举 */
export enum IpcReturnStatus {
    /** 成功 */
    success = "success",
    /** 失败 */
    fail = "fail",
    /** 错误 */
    error = "error"
}

export interface IpcReturnDBKey extends IpcReturnBase {
    db_key: string
}

/** 反馈一个对象 */
export interface IpcReturnValue<TValue> extends IpcReturnBase {
    /** 返回的值 */
    value?: TValue
}

interface SendOption<K extends keyof IpcSendTypes> {
    channel: K,
    return_key: string,
    timeout: number
}

/**
 * 软件里前后台处理交互的辅助工具
 */
class ipcHelper {

    /** 安装VUE插件 */
    public static install(vue: any) {
        const _ipcHelper = new ipcHelper();

        Object.defineProperty(
            vue.prototype,
            '$ipcR',
            {
                get(): ipcHelper { return _ipcHelper; }
            }
        );
    }

    /*public send(channel: string, ...args: any[]): Promise<any>;
    public send(options: ipcHandle, ...args: any[]): Promise<any>;*/


    /**
     * 发起一个与后台主线程的交互。（简化的异步处理）
     * @param channel 交互的频道
     * @param arg 交互参数
     * @param args 其它参数
     */
    public send<K extends keyof IpcSendTypes>(
        channel: K,
        arg?: IpcSendTypes[K]["arg"],
        ...args: any[]
    ): Promise<IpcSendTypes[K]["ret"]>;


    /**
     * 发起一个与后台主线程的交互。（简化的异步处理）
     * @param options 交互的配置
     * @param arg 交互参数
     * @param args 其它参数
     */
    public send<K extends keyof IpcSendTypes>(
        options: SendOption<K>,
        arg?: IpcSendTypes[K]["arg"],
        ...args: any[]
    ): Promise<IpcSendTypes[K]["ret"]>;

    // /**
    // * 发起一个与后台主线程的交互。（简化的异步处理）用于旧兼容
    // * @param channel 交互的频道
    // * @param args 交互参数
    // */
    //public send(channel: string, ...args: any[]): Promise<any>;

    /**
     * 发起一个与后台主线程的交互。（简化的异步处理）
     * @param options 交互参数
     * @param args 后台主线程接受参数
     */
    public send(
        options: ipcSendOptions | string,
        ...args: any[]
    ) {
        let {
            channel,
            return_key = "ret",
            timeout = -1,
            only_resolve = false
        } = _.isString(options) ? { channel: options } : options;

        return new Promise<any>((resolve, reject) => {
            let listener = (event: Event, res: any) => {
                if (only_resolve || !_.has(res, "status") || _.get(res, "status") == IpcReturnStatus.success) {
                    resolve(res);
                }
                else if (_.has(res, "status")) {
                    reject(res);
                }
            };
            let return_channel = channel + "-" + return_key;

            ipcRenderer.once(return_channel, listener);
            ipcRenderer.send(channel, ...args);
        });
    }

}

Vue.use(ipcHelper)